﻿using InTheHand.Net;
using InTheHand.Net.Bluetooth;
using InTheHand.Net.Sockets;
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Sharpimeter.Model
{
    public class OnyxII
    {

        private IMode Mode;
        private BluetoothClient Client;
        private BluetoothAddress MacAdress;
        private string PinCode;

        public OnyxII.StartReadingHandler OnStartReading {get; set;}
        public delegate void StartReadingHandler();
        public OnyxII.NewReadingHandler OnReading { get; set; }
        public delegate void NewReadingHandler(OnyxReading reading);
        public OnyxII.EndReadingSession OnEndReading { get; set; }
        public delegate void EndReadingSession();

        public OnyxII(string macAdress, string pinCode)
        {
            Client = new BluetoothClient();
            this.MacAdress = BluetoothAddress.Parse(macAdress);
            this.PinCode = pinCode;
        }

        public bool Connect()
        {
            if (!Pair())
            {
                return false;
            }
            else if (Client.Connected)
            {
                return true;
            }

            // If not connected try to connect
            Client = new BluetoothClient();
            Console.WriteLine("Waiting for device " + MacAdress + "");
            while (!Client.Connected)
            {
                try
                {
                    Client.Connect(new BluetoothEndPoint(MacAdress, BluetoothService.SerialPort));
                    if (Client.Connected)
                    {
                        return true;
                    }
                }
                catch (SocketException e)
                {
                    System.Diagnostics.Debug.WriteLine("not connected error: " + e.ErrorCode.ToString());
                }
                Console.Write(".");
                System.Threading.Thread.Sleep(500);
            }
            return false;
        }
        
        public bool DiscoverAndPair()
        {
            while (true)
            {
                BluetoothDeviceInfo[] peers = Client.DiscoverDevices();
                foreach (BluetoothDeviceInfo peer in peers)
                {
                    if (peer.DeviceAddress == MacAdress)
                    {
                        Console.WriteLine("Found " + peer.DeviceAddress.ToString());
                        if (Pair())
                        {
                            Console.WriteLine("Device is paired!");
                            return true;
                        }
                        else
                        {
                            Console.WriteLine("Could not pair the device!");
                        }
                    }
                }
            }
        }

        // Pair device if not paired
        public bool Pair()
        {
            if (this.GetRemembered())
            {
                return true;
            }
            else if (BluetoothSecurity.PairRequest(this.MacAdress, this.PinCode))
            {
                return true;
            }
            return false;
        }
        
        // Check if device is paired
        public bool GetRemembered()
        {
            if ((new BluetoothDeviceInfo(this.MacAdress)).Remembered)
            {
                return true;
            }
            return false;
        }

        

        public bool Disconnect()
        {
            Client.Close();
            if (Client.Connected) {
                return false;
            }
            return true;
        }

        public bool UnPair()
        {
            BluetoothSecurity.RemoveDevice(this.MacAdress);
            if ((new BluetoothDeviceInfo(this.MacAdress)).Remembered)
            {
                return false;
            }
            return true;
        }

        public DateTime SetTime()
        {
            DateTime date = new DateTime();
            return date;
        }

        public bool IsPaired()
        {
            if (Client.Authenticate)
            {
                return true;
            }
            return false;
        }

        public void Read()
        {
            Mode.read();
        }

        public bool EndRead() 
        {
            return false;
        }

        public void SetMode(int mode) 
        {
            switch (mode)
            {
                case 8:
                    this.Mode = new Mode8(this.Client, this);
                    break;
                default:
                    System.Diagnostics.Debug.WriteLine("Unsupported mode: " + (mode));
                    break;
            }
        }


        // 6 bytes date to datetime
        public DateTime ConvertBytesToDate(byte[] bytestream)
        {
            return new DateTime(2000 + Convert.ToInt16(bytestream[0]),  /* 2000 + Year */
                                       Convert.ToInt16(bytestream[1]),  /* Month */
                                       Convert.ToInt16(bytestream[2]),  /* Day */
                                       Convert.ToInt16(bytestream[3]),  /* Hour */
                                       Convert.ToInt16(bytestream[4]),  /* Minute */
                                       Convert.ToInt16(bytestream[5])); /* Second */
        }

        // datetime to 6 bytes date
        public Byte[] ConvertDateToBytes(DateTime date)
        {
            Byte[] result = new Byte[6];
            result[0] = Convert.ToByte(date.Year - 2000);
            result[1] = Convert.ToByte(date.Month);
            result[2] = Convert.ToByte(date.Day);
            result[3] = Convert.ToByte(date.Hour);
            result[4] = Convert.ToByte(date.Minute);
            result[5] = Convert.ToByte(date.Second);
            return result;
        }

        public void StartOximeter()
        {
            Console.WriteLine("Searching for device with mac-adress: " + this.MacAdress.ToString() + " pin: " + this.PinCode.ToString());

            DiscoverAndPair();

            while (true)
            {
                if (Connect())
                {
                    Console.WriteLine("Connected");

                    SetMode(8);
                    OnStartReading = startReading;
                    OnReading = newReading;
                    OnEndReading = endReading;
                    Read();
                    Disconnect();
                }
                else
                {
                    Console.WriteLine("Not connected");
                }
                System.Threading.Thread.Sleep(7000);
            }
        }

        public static void startReading()
        {
            Console.WriteLine("Öppnar databasen");
            DatabaseConnection.Instance.Open();
        }

        public static void endReading()
        {
            Console.WriteLine("Stänger databasen");
            DatabaseConnection.Instance.Close();
        }

        public static void newReading(OnyxReading reading)
        {
            try
            {
                Config config = new Config();
                MySqlCommand cmd = new MySqlCommand();
                cmd.Connection = DatabaseConnection.Instance;
                string sqlquery = "INSERT INTO reading VALUES (null, {0}, {1}, {2}, '{3}', {4})";
                string dateString = reading.Time.ToString("yyyy-MM-dd HH:mm:ss");
                cmd.CommandText = String.Format(sqlquery, config.GetPatientID(), reading.Pulse.ToString(), reading.SpO.ToString(), dateString, reading.GoodReading.ToString());
                cmd.ExecuteNonQuery();
            }
            catch (MySqlException ex)
            {
                Console.WriteLine("Error: {0}", ex.ToString());
            }
            Console.WriteLine("Time {0}, Pulse {1}, SpO {2}, Kvalitet {3}", reading.Time.ToString("yyyy-MM-dd H:mm:ss"), reading.Pulse, reading.SpO, reading.GoodReading.ToString());
        }
    }
}
